/**
 * path：Node.js path 模块提供了一些用于处理文件路径的小工具
 * 可以访问此链接了解：https://www.runoob.com/nodejs/nodejs-path-module.html
 * 
 * clean-webpack-plugin
 * 在使用webpack打包时，打包后的文件名如果一样，那么每次打包后，新生成的文件就会将之前打包的文件覆盖掉，
 * 但是如果给输出的文件名设置根据内容生成的hash值后，由于每次打包后生成的文件名的hash值会不一样，
 * 这样就不会因文件名相同而覆盖原来的文件，在文件目录中出现了一些多余的文件；
 * 如果每次都手动清除这些多余文件也是很麻烦的，
 * 
 * uglify：压缩JS代码
 * 
 * html_webpack_plugins 定义
 * 
 * template：本地模板文件的位置，支持加载器(如handlebars、ejs、undersore、html等)
 * filename：输出文件的文件名称，默认为index.html，不配置就是该文件名；此外，还可以为输出文件指定目录位置（例如'html/index.html'）
 * inject：向template或者templateContent中注入所有静态资源，不同的配置值注入的位置不经相同。
 * 1、true或者body：所有JavaScript资源插入到body元素的底部
 * 2、head: 所有JavaScript资源插入到head元素中
 * 3、false： 所有静态资源css和JavaScript都不会注入到模板文件中
 * 
 * chunks: 允许插入到模板中的一些chunk，不配置此项默认会将entry中所有的thunk注入到模板中。
 * 在配置多个页面时，每个页面注入的thunk应该是不相同的，需要通过该配置为不同页面注入不同的thunk
 * 
 * purifycss-webpack: css未使用代码清除
 * 
 * ImageminPlugin: 图片压缩
 */
const path = require("path");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const uglify = require('uglifyjs-webpack-plugin');
const htmlPlugin = require('html-webpack-plugin');
const extractTextPlugin = require("extract-text-webpack-plugin");
const glob = require('glob');
const webpack = require('webpack');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;

const srcDir = path.resolve(process.cwd(), 'src');// src文件夹路径
const nodeModPath = path.resolve(__dirname, './node_modules');// node依赖文件夹路径
let publicPath = '';// 静态资源路径
let isDeploy = false;// 是否在正式环境中

// 根据不同的环境 配置参数
switch (process.env.NODE_ENV) {
  case 'dev':
    publicPath = '/';
    isDeploy = false;
    break;
  case 'formal':
    publicPath = 'http://127.0.0.1:8080/';
    break;
}

function resolve(dir) {
  return path.join(__dirname, '.', dir)
}

// 入口文件配置变量
let EntriesList = {};

// 获取所有JS文件
let entries = function () {
  // 获取当前项目js文件夹的绝对路径
  let jsDir = path.resolve(srcDir, 'js');
  // 同步获取匹配文件列表
  let entryFiles = glob.sync(jsDir + '/*.{js,jsx}');
  let map = {};

  for (let i = 0; i < entryFiles.length; i++) {
    let filePath = entryFiles[i];

    let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
    map[filename] = filePath;
  }
  return map;
}

// 动态生成HTML
let html_plugins = function () {
  // 获取对应目录下的所有文件，返回一个数组
  let entryHtml = glob.sync(srcDir + '/page/*.ejs');
  let r = []
  // 获取所有对应的JS文件
  let entriesFiles = entries();

  for (let i = 0; i < entryHtml.length; i++) {
    let filePath = entryHtml[i];
    let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));

    let conf = {
      // 需要编译的模版文件路径
      template: filePath,
      // 编译后的输出路径
      filename: filename + '.html',
      minify: {
        //移除HTML中的注释
        removeAttributeQuotes: true,
        //删除空白符与换行符
        collapseWhitespace: true,
      }
    }

    //如果和入口js文件同名
    if (filename in entriesFiles) {
      // 文件注入位置（详情查看html-webpack-plugin文档）
      conf.inject = 'body';
      /**
       * chunks：对应着入口文件的key, chunks接受一个数组，根据里面的块对应注入文件中， inject：则是注入的位置
       * 比方:
       * entry: {
       *  '模块名': '对应文件地址'
       * }
       * 则key等于模块名
       */
      conf.chunks = [filename, 'common'];
      // 给对应的文件注入对应的JS
      EntriesList[filename] = path.join(__dirname, `./src/js/${filename}.js`);
    }

    // 生成html模板文件
    r.push(new htmlPlugin(conf))
  }
  return r
}

// 插件配置
let plugins = [];

plugins.push(
  // new CleanWebpackPlugin(),
  new uglify({
    compress: {// 压缩代码
      // 移除没被引用的代码
      dead_code: true,
      // 当删除没有用处的代码时，显示警告
      warnings: false,
      // 当do、while 、 for循环的判断条件可以确定是，对其进行优化
      loops: true
    },
    // 混淆,并排除关键字
    except: ['$', 'exports', 'require']
  }),
  //在编译出现错误时，使用 NoEmitOnErrorsPlugin 来跳过输出阶段。这样可以确保输出资源不会包含错误。对于所有资源，统计资料(stat)的 emitted 标识都是 false。
  new webpack.NoEmitOnErrorsPlugin(),
  // CSS文件分离
  new extractTextPlugin('css/[hash:8].[name].css'),
  // 自动加载模块，而不必到处 import 或 require
  new webpack.ProvidePlugin({
    $: 'jquery'
  }),
  // base64之外的图片处理
  new ImageminPlugin({
    disable: process.env.NODE_ENV === 'dev',// 测试环境不打开 其他环境打开 false：压缩 true: 不压缩
    pngquant: {
      quality: '70-80',// 成像质量范围
    }
  }),
  /**
   * CommonsChunkPlugin 插件，是一个可选的用于建立一个独立文件(又称作 chunk)的功能，这个文件包括多个入口 chunk 的公共模块。
   * 
   *   minChunks:
   *   在传入  公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。
   *   数量必须大于等于2，或者少于等于 chunks的数量
   *   传入 `Infinity` 会马上生成 公共chunk，但里面没有模块。
   *   你可以传入一个 `function` ，以添加定制的逻辑（默认是 chunk 的数量）
   */
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: Infinity
  })
);

module.exports = {
  /**
   * 入口文件的配置项
   * 
   * entry里面的配置为键值对即:
   * 
   * entryA: './src/entryA.js'
   * entryB: './src/entryB.js'
   */

  entry: Object.assign(EntriesList,
    // 用到什么公共lib（例如jquery.js），就把它加进vendor去，目的是将公用库单独提取打包
    {
      'common': ['jquery']
    }
  ),

  /**
   * 出口文件的配置项
   * 
   * __dirname 表示当前文件所在的目录的绝对路径 比方现在在F盘的webpack下面的webpack-lianxi则返回
   * F:\webpack\webpack-lianxi
   * 
   * [name]的意思是根据入口文件的名称，打包成相同的名称，有几个入口文件，就可以打包出几个文件
   */
  output: {
    // 打包的路径位置 
    path: path.resolve(__dirname, 'dist'),
    // 打包的文件名称 
    filename: 'js/[hash:8].[name].js',
    // 静态资源路径
    publicPath,
  },
  // 模块：例如解读CSS,图片如何转换，压缩
  module: {
    rules: [
      // sass && css文件处理
      {
        test: /\.(sa|sc|c)ss$/,
        use: extractTextPlugin.extract({
          fallback: "style-loader",//使用extractTextPlugin.extract时最优先使用的处理模块
          use: [
            {
              loader: 'css-loader',
              options: {
                url: false,
                minimize: isDeploy,
                importLoaders: 2,//在 css-loader 前应用的 loader 的数量
              }
            },
            {
              loader: 'postcss-loader'
            },
            {
              loader: "sass-loader"
            }
          ]
        })
      },
      // less文件处理
      {
        test: /\.less$/,
        use: extractTextPlugin.extract({
          fallback: "style-loader",
          use: [{
            loader: "css-loader",
            options: {
              url: false,
              minimize: isDeploy,
              importLoaders: 1
            }
          },
          {
            loader: "postcss-loader"
          },
          {
            loader: "less-loader"
          }],
        })
      },
      // 图片处理
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        // //简写写法
        // use: [
        //     //小于50KB的图片会自动转成dataUrl，
        //     'url-loader?limit=50000&name=images/[hash:8].[name].[ext]'
        // ],
        use: [
          {
            loader: 'url-loader',
            options: {
              esModule: false, // 这里设置为false 
              name: '[hash:8].[name].[ext]',//设置抽离打包图片的名称--[path] 获取文件的绝对路径 [hash:8] 哈希值:多少位数 [name]文件名 [ext]用来获取图片的后缀
              limit: 50000,//限制图片大小 <= 50kb 进行base64编码（小于50kb打包进js文件）--测试时根据图片的大小调整
              outputPath: 'img'//设置输出文件夹名称，这个文件夹会与主入口文件在同一路径下
            }
          }
        ]
      },
      //媒体文件处理
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240,
              fallback: {
                loader: 'file-loader',
                options: {
                  name: 'media/[hash:8].[name].[ext]'
                }
              }
            }
          }
        ]
      },
      // 字体处理
      {
        test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240,
              fallback: {
                loader: 'file-loader',
                options: {
                  esModule: false,
                  name: 'fonts/[hash:8].[name].[ext]'
                }
              }
            }
          }
        ]
      },
      // html文件图片路径处理
      {
        test: /\.(htm|html)$/,
        loader: 'html-loader'
      },
      // 使用babel将ES6编译转换ES5
      {
        test: /\.(jsx|js)$/,
        use: {
          loader: 'babel-loader',
        }
      },
      {
        test: /\.ejs$/,
        loader: "art-template-loader",
      }
    ]
  },
  resolve: {
    /**
     * 使用此选项，会覆盖默认数组，这就意味着 webpack 将不再尝试使用默认扩展来解析模块。对于使用其扩展导入的模块，
     * 例如，import SomeFile from "./somefile.ext"，要想正确的解析，一个包含“*”的字符串必须包含在数组中。
     * 比方下面列表有 .jpg 那么 import img from "./src/1.jpg" 可以变成 import img from "./src/1"
     */
    extensions: ['.js', '.css', '.json', '.less', '.sass', '.scss', '.tpl', '.jpg', '.png', '.gif', '.jpge', '.svg'],
    // 设置匹配规则范围
    modules: [srcDir, nodeModPath],
    // 配置路径别名
    alias: {
      'src': resolve('src'),
      'jquery': "src/js/lib/jquery-1.12.4.js",
      'component': resolve('src/component'),
    }
  },
  // 插件，用于生产模版和各项功能
  plugins: plugins.concat(html_plugins()),
  // 配置webpack开发服务功能
  devServer: {
    // 设置基本目录结构
    contentBase: path.resolve(__dirname, 'dist'),
    // 服务器的IP地址，可以使用IP也可以使用localhost
    host: 'localhost',
    // 服务端压缩是否开启
    compress: true,
    // 配置服务端口号
    port: 1758,
    // 指定默认访问文件
    // index: '/page/index.html',
  },
  // 监听修改自动打包
  // watch: true   
}